package valerij_timakov.home_finances.application_handlers;

import java.util.Iterator;
import java.util.Map;

import javax.faces.FacesException;
import javax.faces.application.NavigationHandler;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;

import valerij_timakov.home_finances.exceptions.AppException;
import valerij_timakov.home_finances.exceptions.AppExceptionNotAuthorized;

public class AppExceptionHandler extends ExceptionHandlerWrapper {
	
	private ExceptionHandler wrapped;
	
	public AppExceptionHandler(ExceptionHandler wrapped) {
		this.wrapped = wrapped;
	}
	
	@Override
	public ExceptionHandler getWrapped() {
		return this.wrapped;
	}
	
	@Override
	public void handle() throws FacesException {
		Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();
		while (i.hasNext()) {
			ExceptionQueuedEvent event = i.next();
			ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();	
			Throwable t = context.getException();
			AppException appException = getAppExceptionCause(t);
			if (appException != null) {
				FacesContext fc = FacesContext.getCurrentInstance();
				Map<String, Object> requestMap = fc.getExternalContext().getRequestMap();
				NavigationHandler nav = fc.getApplication().getNavigationHandler();
				try {
					requestMap.put("throwedViewId", appException.getThrowedViewId());
					requestMap.put("userMessage", appException.getUserMessage());
					nav.handleNavigation(fc, null, appException.getErrorShowViewId());
					fc.renderResponse();
				} finally {
					i.remove();
				}
			}
		}
		getWrapped().handle();
	}
	
	private AppException getAppExceptionCause(Throwable t) {
		if (t instanceof AppException) {
			return (AppException) t;
		}
		while(t.getCause() != null) {
			if (t.getCause() instanceof AppException) {
				return (AppException) t.getCause();
			}
			t = t.getCause();
		}
		return null;
	}
}
